/*==============================================
  JT-LCD Touch & Display Module Demo.
  128 X 128 Pixel Mono LCD + 8Key Touch screen.

  (주)우정하이텍 연구소
   T) 031-736-0162
  ===============================================*/

#include <Arduino.h>
#include <avr/wdt.h>
#include <SoftwareSerial.h>

#define off 0
#define on 1
#define error 0
#define good 1

#define SINGLE 0
#define DOUBLE 1

#define ACK 0x06
#define NAK 0x15
#define STX 0x02
#define ETX 0x03

///

#define LCD_SELECT   0
#define USM1_SELECT  1
#define USM2_SELECT  2
#define Reserved_2   3

///

#define USM_AUTO_MODE '1'
#define USM_SINGLE_MODE '2'

//--------------

byte CLR_SCR(void);
void MenuDisplay(void);

unsigned char TouchState = 0;   // 터치 상태 버퍼.
unsigned char TxBuffer[200];    // 송신 버퍼.
unsigned char BeepToggleFlag = on, ClearFlag = off;

unsigned int UBRR0_57600, UBRR0_19200;

void TouchKey_ActiveControl(unsigned char KeyState);
void USM_InitialAll(void);

/*=============================
 * setup();
 * 시스템 설정을 초기화 한다.
 =============================*/
void setup(void)
{
  wdt_disable();
  
  Serial.begin(19200);
  UBRR0_19200 = UBRR0/2;

  Serial.begin(57600);
  UBRR0_57600 = UBRR0;
  Serial.setTimeout(1500);

  // port initial.
  pinMode(13, OUTPUT);    // PB5 is Led : High active.
  digitalWrite(13, LOW);  // LED off

  // Serial channel select Low bit
  pinMode(2, OUTPUT);      // PD2 is event
  digitalWrite(2, LOW);  // SEL0 off
  // Serial channel select High bit
  pinMode(3, OUTPUT);      // PD3 is event
  digitalWrite(3, LOW);  // SEL1 off

  SerialChannelSelect(LCD_SELECT);//USM_SELECT

  // JT-LCD Touch event input
  pinMode(4, INPUT);      // PD4 is event : Low active.
  
  // Ultrasonic Sensor Module 1 Event input
  pinMode(5, INPUT);      // PD5 is event : Low active.

  // Ultrasonic Sensor Module 2 Event input
  pinMode(6, INPUT);      // PD6 is event : Low active.

  //wdt_enable(WDTO_4S); // WDT enable 4Sec.
  //wdt_reset();
  
  delay(1000);  // LCD 초기화 대기.
  wdt_reset();
  TouchBeepFrequencySet(14);
  BeepToggleFlag = on;
  wdt_reset();
  USM_InitialAll();
}

//---------------------------------------------

/*=======================================================================
 * Serial Channel Select function.
 *  => Serial port 확장용 보드를 사용할 경우 PD2(2), PD3(3)을 이용하여 
 *      4개의 channel 을 선택적으로 사용한다.
 * channel 번호를 인자로 받아 4개의 채널을 선택 할 수 있으며, 
 *   PD2 는 D0, PD3 는 D1 이 할당 된다.
 * D1, D0 = PD3, PD2 = 0,0 : channel 0.
 * D1, D0 = PD3, PD2 = 0,1 : channel 1.
 * D1, D0 = PD3, PD2 = 1,0 : channel 2.
 * D1, D0 = PD3, PD2 = 1,1 : channel 3.
 =======================================================================*/
void SerialChannelSelect(char chanel)
{
  if(chanel == 0)
  {
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
  }
  else if(chanel == 1)
  {
    digitalWrite(2, HIGH);
    digitalWrite(3, LOW);
  }
  else if(chanel == 2)
  {
    digitalWrite(2, LOW);
    digitalWrite(3, HIGH);
  }
  else if(chanel == 3)
  {
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
  }
}


/*=========================================
 * Serial Channel select Baud rate setting
 * ARGV : 0 = JT-LCD = chanel 0, 57600bps.
 *        1 = USM = chanel 1, 19200bps.
 *        2 = Reserved.
 *        3 = Reserved.
 =========================================*/
void DeviceSelect(char sel)
{
  if(sel == 0)
  {
    SerialChannelSelect(LCD_SELECT);
    UBRR0 = UBRR0_57600;
  }
  else if(sel == 1)
  {
    SerialChannelSelect(USM1_SELECT);
    UBRR0 = UBRR0_19200;
  }
  else if(sel == 2)
  {
    SerialChannelSelect(USM2_SELECT);
    UBRR0 = UBRR0_19200;
  }
  else if(sel == 3)
  {
    SerialChannelSelect(3);
  }
}

//---------------------------------------------


/*=============================
 * ACK_Send();
 * ACK 를 송신. 
 ============================*/
void ACK_Send(void)
{
  TxBuffer[0] = ACK;
  Serial.write(TxBuffer, 1);
  Serial.flush(); // 전송 완료를 기다림.
}

/*=============================
 * NAK_Send();
 * ACK 를 송신. 
 ============================*/
void NAK_Send(void)
{
  TxBuffer[0] = NAK;
  Serial.write(TxBuffer, 1);
  Serial.flush(); // 전송 완료를 기다림.
}


/*=============================
 * AckNak_Check();
 * ACK 또는 NAK 수신 & 확인 
 *    return value
 * ACK 수신 : ACK 
 * NAK 수신 : NAK 
 * Rx timeout : false(0) 
 ============================*/
byte AckNak_Check(void)
{
  unsigned char DumyBuf[5],leng;
  
  leng = Serial.readBytes(DumyBuf, 1);
  if(leng == 1)
  {
    if(DumyBuf[0] == ACK) return (ACK);
    else if(DumyBuf[0] == NAK) return (NAK);
    else return(false);
  }
  else return(false);
}


/*====================================
 * CLR_SCR();
 * 화면 전체를 한번에 지운다.
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ====================================*/
byte CLR_SCR(void)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x34;
  sum = 0x34;
  TxBuffer[2] = 0x42;
  sum += 0x42;
  TxBuffer[3] = 0x33;
  sum += 0x33;
  TxBuffer[4] = ETX;
  sum += ETX;
  TxBuffer[5] = sum;
  Serial.write(TxBuffer, 6);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*====================================
 * DrawDot();
 * 입력한 좌표에 점 한개를 찍는다.
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ====================================*/
char DrawDot(byte x, byte y)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x36;
  sum = 0x36;
  TxBuffer[2] = 0x41;
  sum += 0x41;
  TxBuffer[3] = 0x31;
  sum += 0x31;
  TxBuffer[4] = 0x30 + x;
  sum += TxBuffer[4];
  TxBuffer[5] = 0x30 + y;
  sum += TxBuffer[5];
  TxBuffer[6] = ETX;
  sum += ETX;
  TxBuffer[7] = sum;
  Serial.write(TxBuffer, 8);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*====================================
 * DrawLine();
 * 입력한 두개의 좌표 사이에 선을 그린다.
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ====================================*/
char DrawLine(byte x1, byte y1, byte x2, byte y2)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x38;
  sum = 0x38;
  TxBuffer[2] = 0x41;
  sum += 0x41;
  TxBuffer[3] = 0x32;
  sum += 0x32;

  TxBuffer[4] = 0x30 + x1;
  sum += TxBuffer[4];
  TxBuffer[5] = 0x30 + y1;
  sum += TxBuffer[5];

  TxBuffer[6] = 0x30 + x2;
  sum += TxBuffer[6];
  TxBuffer[7] = 0x30 + y2;
  sum += TxBuffer[7];

  TxBuffer[8] = ETX;
  sum += ETX;
  TxBuffer[9] = sum;
  Serial.write(TxBuffer, 10);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*====================================
 * DrawBox();
 * 입력한 두개의 좌표 (좌상,우하) 사이에 
 * 박스를 그린다.
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ====================================*/
byte DrawBox(byte x1, byte y1, byte x2, byte y2)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x38;
  sum = 0x38;
  TxBuffer[2] = 0x41;
  sum += 0x41;
  TxBuffer[3] = 0x34;
  sum += 0x34;

  TxBuffer[4] = 0x30 + x1;
  sum += TxBuffer[4];
  TxBuffer[5] = 0x30 + y1;
  sum += TxBuffer[5];

  TxBuffer[6] = 0x30 + x2;
  sum += TxBuffer[6];
  TxBuffer[7] = 0x30 + y2;
  sum += TxBuffer[7];

  TxBuffer[8] = ETX;
  sum += ETX;
  TxBuffer[9] = sum;
  Serial.write(TxBuffer, 10);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*====================================
 * DrawCircle();
 * 입력한 좌표를 중심으로 입력된 반지름의
 * 원을 그린다.
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ====================================*/
byte DrawCircle(byte x, byte y, byte r)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x37;
  sum = 0x37;
  TxBuffer[2] = 0x41;
  sum += 0x41;
  TxBuffer[3] = 0x33;
  sum += 0x33;

  TxBuffer[4] = 0x30 + x;
  sum += TxBuffer[4];
  TxBuffer[5] = 0x30 + y;
  sum += TxBuffer[5];
  TxBuffer[6] = 0x30 + r;
  sum += TxBuffer[6];

  TxBuffer[7] = ETX;
  sum += ETX;
  TxBuffer[8] = sum;
  Serial.write(TxBuffer, 9);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*===============================================
 * DrawString();
 * 입력한 좌표를 시작점으로 한글 또는 영문을
 * 표시한다. 이때, 표준 사이즈의 문자는 "SINGLE"을
 * 2배 확대 문자는 "DOUBLE"을 사용하여 call 한다.
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ================================================*/
byte DrawString(byte x, byte y, bool Double_Single, unsigned char *str, unsigned char leng)
{
  unsigned char sum, i = 0, j;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x31 + 5 + leng;
  TxBuffer[2] = 0x42;

  if (Double_Single == SINGLE) TxBuffer[3] = 0x31;
  else TxBuffer[3] = 0x32;

  TxBuffer[4] = 0x30 + x;
  TxBuffer[5] = 0x30 + y;

  for (i = 0; i < leng; i++)
  {
    TxBuffer[i + 6] = *str;
    str++;
  }

  TxBuffer[i + 6] = ETX;

  sum = 0;
  for (j = 1; j <= (leng + 6); j++) sum += TxBuffer[j];

  TxBuffer[i + 7] = sum;
  Serial.write(TxBuffer, i + 8);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*===============================================
 * BrightControl();
 * 입력한 값으로 밝기를 설정한다.
 * 입력 범위 : 0% ~ 100%
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ================================================*/
byte BrightControl(byte bright)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x34;
  sum = 0x34;
  TxBuffer[2] = 0x43;
  sum += 0x43;
  TxBuffer[3] = 0x30 + bright;
  sum += TxBuffer[3];
  TxBuffer[4] = ETX;
  sum += ETX;
  TxBuffer[5] = sum;
  Serial.write(TxBuffer, 6);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*===============================================
 * ContrastControl();
 * 입력한 값으로 콘트라스트를 설정한다.
 * 이 값이 높으면 진해지나 너무 높으면 전체적으로 
 * 검정색이 되고, 낮으면 어두워진다.
 * 적절한 값을 선택한다.
 * 입력 범위 : 1 ~ 64
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 ================================================*/
byte ContrastControl(byte cont)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x35;
  sum = 0x35;
  TxBuffer[2] = 0x47;
  sum += 0x47;
  TxBuffer[3] = 0x31;
  sum += 0x31;
  TxBuffer[4] = 0x30 + cont;
  sum += TxBuffer[4];
  TxBuffer[5] = ETX;
  sum += ETX;
  TxBuffer[6] = sum;
  Serial.write(TxBuffer, 7);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*=======================================================
 * TouchBeepFrequencySet();
 * 터치시에 발생하는 터치 효과 음의 음색(주파수)를 선택 한다.
 * 4 옥타브의 음 중에서 선택할수 있으며 끌수 있다. 
 * 적절한 값을 선택하여 설정한다.
 * 입력 범위 : 0 ~ 28 (0 = 음 소거)
 *    return value
 * ACK 응답 : true(1)
 * NAK 응답 or Rx timeout : false(0)
 =======================================================*/
byte TouchBeepFrequencySet(byte freq)
{
  unsigned char sum = 0;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x34;
  sum = 0x34;
  TxBuffer[2] = 0x44;
  sum += 0x44;
  TxBuffer[3] = 0x30 + freq;
  sum += TxBuffer[3];
  TxBuffer[4] = ETX;
  sum += ETX;
  TxBuffer[5] = sum;
  Serial.write(TxBuffer, 6);

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}

//---------------------------------------------------------------------------


unsigned int TouchData_Check(void)
{
  unsigned char leng = 0, c, sum;
  unsigned char rx_buffer[10];

  leng = Serial.readBytes(rx_buffer, 7);

  // rx data length check.
  if (leng < 7) return (0);

  sum = 0;
  for (c = 1; c < 6; c++) sum += rx_buffer[c];
  sum &= 0xff;
  if (sum == rx_buffer[6])
  {
    c = (rx_buffer[3] & 0xf) << 4;
    c |= (rx_buffer[4] & 0xf);
    return (0x100 | c);
  }
  else return (0);
}


/*=======================================================
 * TouchDataRead();
 * 터치 이벤트 발생시에 touch data를 읽어오는 명령이다.
 *    return value
 * NAK 응답 or Rx timeout : false(0)
 * 정상 read : true(1)
 *             Touch data는 "TouchState" 변수에 넣는다.
 =======================================================*/
unsigned char TouchDataRead(void)
{
  unsigned char sum = 0;
  unsigned int retData;

  TxBuffer[0] = STX;
  TxBuffer[1] = 0x33;
  sum = 0x33;
  TxBuffer[2] = 0x45;
  sum += 0x45;
  TxBuffer[3] = ETX;
  sum += ETX;
  TxBuffer[4] = sum;
  Serial.write(TxBuffer, 5);
  Serial.flush(); // 전송 완료를 기다림.

  retData = TouchData_Check();
  if (retData == 0) return (false);
  else
  {
    TouchState = (unsigned char)(retData & 0xff);
    return (true);
  }
}

//-----------------------------------------------------------------------------

/*=======================================================
 * Touch test menu 용 Display data.
 =======================================================*/
const unsigned char KeyMsg_1[7] = {'h', '8', '0', ':',' ','X', 0};
const unsigned char KeyMsg_2[7] = {'h', '4', '0', ':',' ','X', 0};
const unsigned char KeyMsg_3[7] = {'h', '2', '0', ':',' ','X', 0};
const unsigned char KeyMsg_4[7] = {'h', '1', '0', ':',' ','X', 0};
const unsigned char KeyMsg_5[7] = {'h', '0', '8', ':',' ','X', 0};
const unsigned char KeyMsg_6[7] = {'h', '0', '4', ':',' ','X', 0};
const unsigned char KeyMsg_7[7] = {'h', '0', '2', ':',' ','X', 0};
const unsigned char KeyMsg_8[7] = {'h', '0', '1', ':',' ','X', 0};

const unsigned char KeyMsg_On[2]  = {'O', 0};
const unsigned char KeyMsg_Off[2] = {'X', 0};

/*=======================================================
 * KeyBox_Display();
 * Touch test menu 용 box Display.
 =======================================================*/
void KeyBox_Display(void)
{
  // Box L1
  delay(20);//100
  if(DrawBox(0,0+2,63-2,31-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box R1
  delay(20);
  if(DrawBox(63+2,0+2,127,31-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box L2
  delay(20);
  if(DrawBox(0,31+2,63-2,63-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box R2
  delay(20);
  if(DrawBox(63+2,31+2,127,63-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box L3
  delay(20);
  if(DrawBox(0,63+2,63-2,95-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box R3
  delay(20);
  if(DrawBox(63+2,63+2,127,95-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box L4
  delay(20);
  if(DrawBox(0,95+2,63-2,127-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  // Box R4
  delay(20);
  if(DrawBox(63+2,95+2,127,127-2) == true) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  delay(20);//100
}

/*=======================================================
 * KeyTestMenu_Display();
 * Touch test menu 용 box 내의 내용 Display.
 =======================================================*/
void KeyTestMenu_Display(void)
{
  DrawString(8,8,SINGLE,KeyMsg_1,6);
  DrawString(8,8+32,SINGLE,KeyMsg_2,6);
  DrawString(8,8+64,SINGLE,KeyMsg_3,6);
  DrawString(8,8+96,SINGLE,KeyMsg_4,6);
  DrawString(8+64,8,SINGLE,KeyMsg_5,6);
  DrawString(8+64,8+32,SINGLE,KeyMsg_6,6);
  DrawString(8+64,8+64,SINGLE,KeyMsg_7,6);
  DrawString(8+64,8+96,SINGLE,KeyMsg_8,6);
}


/*************************************************
 * Main menu 용 Display data.
 * 
 * 아래 한글을 HEX 로 표기한 이유.
 * : 아두이노 스케치 에서는 KS한글코드를 지원하지
 * 않으므로 변환 프로그램 이나 다른 에디터를
 * 사용하여 변환 값을 입력 합니다.
 * (코드 변환 program은 별도로 제공)
 *************************************************/
const unsigned char M_Menu_1[10] = {0xc5,0xcd,0xc4,0xa1,0,};  //"터치";
const unsigned char M_Menu_2[10] = {0xc7,0xa5,0xc1,0xd8,0,};  //"표준";
const unsigned char M_Menu_3[10] = {0xc8,0xae,0xb4,0xeb,0,};  //"확대";
const unsigned char M_Menu_4[10] = "Beep:O";
const unsigned char M_Menu_5[10] = {0xB0,0xC5,0xB8,0xAE,0,};  //"거리";

const unsigned char MSG_Commant_1[32] = {
0xC5,0xCD,0xC4,0xA1,0x20,0xB8,0xAE,0xC5,0xCF,0x20,
0x3A,0x20,0xBE,0xC6,0xB7,0xA1,0x20,0x32,0xC5,0xB0,
0x20,0xB5,0xBF,0xBD,0xC3,0x20,0x4F,0x6E,0x2E,0x20,
0x20,0x20};  //32

///

void USM1_EventOnDisplay(void)
{
  DrawString(8*4,16*6,SINGLE,":On :",5);
}

void USM1_EventOffDisplay(void)
{
  DrawString(8*4,16*6,SINGLE,":Off:",5);
} 

void USM2_EventOnDisplay(void)
{
  DrawString(8*4,16*7,SINGLE,":On :",5);
}

void USM2_EventOffDisplay(void)
{
  DrawString(8*4,16*7,SINGLE,":Off:",5);
} 


/*=======================================================
 * Main_MenuBox_Display();
 * Main menu 용 box & 내용 Display.
 =======================================================*/
void Main_MenuBox_Display(void)
{
//  DrawBox(0,0+2,63-2,31-2);     // Box L1
//  DrawBox(63+2,0+2,127,31-2);   // Box R1
//  DrawBox(0,31+2,63-2,63-2);    // Box L2
//  DrawBox(63+2,31+2,127,63-2);  // Box R2

  DrawBox(0+4,0+4,64-4,32-4);   // Box L1
  DrawBox(64+4,0+4,128-4,32-4);   // Box R1
  DrawBox(0+4,32+4,64-4,64-4-2);  // Box L2


  DrawString(16,8,SINGLE,M_Menu_1,4);
  DrawString(16,8+32,SINGLE,M_Menu_2,4);
  //DrawString(16+64,8+32,SINGLE,M_Menu_5,4);
  DrawString(8+64,8,SINGLE,M_Menu_4,5);
  if(BeepToggleFlag == on) DrawString(8+64+(8*5),8,SINGLE,KeyMsg_On,1);
  else DrawString(8+64+(8*5),8,SINGLE,KeyMsg_Off,1);

  DrawString(0,62,SINGLE,MSG_Commant_1,32);//0,70,

  // Ultrasonic Module part display
  DrawLine(4,94,123,94);//4,108,123,108
  DrawString(0,16*6,SINGLE,"USM1:       - Cm",16);//0,16*7
  USM1_EventOffDisplay();
  DrawString(0,16*7,SINGLE,"USM2:       - Cm",16);//0,16*7
  USM2_EventOffDisplay();
}

///

/*=============================================
 * TouchTestProcess();
 * Touch 동작을 시험하는 루틴이다.
 * 이 루틴에서 리턴 하려면 제일 아래쪽의 2키를 
 * 동시에 터치한다.
 =============================================*/
void TouchTestProcess(void)
{
  CLR_SCR();
  KeyBox_Display();
  KeyTestMenu_Display();
  TouchKey_ActiveControl(0xff);
  while(1)
  {
    wdt_reset();
    
    // touch data read test
    if (digitalRead(4) == LOW) // 터치 이벤트 발생 여부 확인.
    {
      if (TouchDataRead() == true) // 터치 데이터 읽기.
      {
        if(TouchState == 0x11) 
        {
          digitalWrite(13, LOW);
          return;
        }
        
        if (TouchState == 0) digitalWrite(13, LOW);
        else digitalWrite(13, HIGH);
  
        if(TouchState & 0x80)
        {
          DrawString(8+(8*5),8,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+(8*5),8,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x40)
        {
          DrawString(8+(8*5),8+32,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+(8*5),8+32,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x20)
        {
          DrawString(8+(8*5),8+64,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+(8*5),8+64,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x10)
        {
          DrawString(8+(8*5),8+96,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+(8*5),8+96,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x08)
        {
          DrawString(8+64+(8*5),8,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+64+(8*5),8,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x04)
        {
          DrawString(8+64+(8*5),8+32,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+64+(8*5),8+32,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x02)
        {
          DrawString(8+64+(8*5),8+64,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+64+(8*5),8+64,SINGLE,KeyMsg_Off,1);
        }
  
        if(TouchState & 0x01)
        {
          DrawString(8+64+(8*5),8+96,SINGLE,KeyMsg_On,1);
        }
        else
        {
          DrawString(8+64+(8*5),8+96,SINGLE,KeyMsg_Off,1);
        }
      }
    }
  }
}


/*=============================================
 * MainMenuDisplay();
 * 화면을 클리어하고 main menu 를 display 한다.
 =============================================*/
void MainMenuDisplay(void)
{
  wdt_reset();
  CLR_SCR();
  Main_MenuBox_Display();
  TouchKey_ActiveControl(0xc8);
  ClearFlag = off;
}

//---------------------------------------------

unsigned char FirstDistStr[3] = {0,0,0};

/*==================================================
 * 기능 : 초음파 모듈에 거리 데이터를 요청하고 수신 한다.
 * 
 * 설명 : 여러개의 거리 데이터가 수신 될 수 있으며 
 * 데모 코드는 가장 가까운 데이터 하나만 리턴 한다.
 =================================================*/
unsigned int DistanceData_Check(void)
{
  unsigned char leng = 0, c, sum,rx_length;
  unsigned char rx_buffer[50];
  unsigned int distance;

  Serial.readBytes(rx_buffer, 2);
  rx_length = rx_buffer[1];
  leng = (rx_length - 0x30) + 1;
  Serial.readBytes(rx_buffer, leng);

  sum = rx_length;
  for (c = 0; c < leng-1; c++) sum += rx_buffer[c];
  
  if(sum == rx_buffer[leng-1])
  {
    ACK_Send();
    
    if(rx_buffer[1] != 0x30)
    {
      FirstDistStr[0] = rx_buffer[2];
      FirstDistStr[1] = rx_buffer[3];
      FirstDistStr[2] = rx_buffer[4];
      distance = (rx_buffer[2] & 0xf) * 100;
      distance += ((rx_buffer[3] & 0xf) * 10);
      distance += (rx_buffer[4] & 0xf);
      return(distance);      
    }
    else 
    {
      NAK_Send();
      return(false);
    }
  }
  else 
  {
    NAK_Send();
    return(false);
  }
}


//---------------------------------------------------


/*=============================================
 * 초음파 모듈 의 모드를 변경 
 * : 다중 모듈의 사용을 위하여 
 *    read 한다.
 * 결과는 Cm 단위의 정수를 ARG에 넣는다.
 * return value : process OK : true.
 *                process Error = false.
 =============================================*/
char USM_ModeSet(unsigned char mode, char USM_chanel_NO)
{
  unsigned char sum = 0;

  DeviceSelect(USM_chanel_NO);
  
  TxBuffer[0] = STX;
  TxBuffer[1] = 0x34;
  sum = 0x34;
  TxBuffer[2] = 0x4E;
  sum += 0x4E;
  TxBuffer[3] = mode;
  sum += TxBuffer[3];
  TxBuffer[4] = ETX;
  sum += ETX;
  TxBuffer[5] = sum;
  Serial.write(TxBuffer, 6);
  Serial.flush(); // 전송 완료를 기다림.

  sum = AckNak_Check();
  DeviceSelect(LCD_SELECT);
  if(sum == ACK) return (true);
  else return (false);
}

/*========================================
 * 기능 : 초음파 드라이브 레인지 변경.
 * 
 * 설정치 : 1 ~ 7 레벨 설정 가능.
 *         1 = 제일 낮음.
 *         7 = 제일 높음.
 =======================================*/
char USM_SensitivitySet(unsigned char sense, char USM_chanel_NO)
{
  unsigned char sum = 0;

  DeviceSelect(USM_chanel_NO);
  
  TxBuffer[0] = STX;
  TxBuffer[1] = 0x34;
  sum = 0x34;
  TxBuffer[2] = 0x44;
  sum += 0x44;
  TxBuffer[3] = sense | 0x30;
  sum += TxBuffer[3];
  TxBuffer[4] = ETX;
  sum += ETX;
  TxBuffer[5] = sum;
  Serial.write(TxBuffer, 6);
  Serial.flush(); // 전송 완료를 기다림.

  sum = AckNak_Check();
  DeviceSelect(LCD_SELECT);
  if(sum == ACK) return (true);
  else return (false);
}



/*=======================================
 * 초음파 모듈 2개를 모두 초기화 한다.
 * 
 * MODE : SINGLE SHOT mode
 * Sensitivity : Level 3
 ======================================*/
void USM_InitialAll(void)
{
  USM_SensitivitySet(3,USM1_SELECT);
  USM_ModeSet(USM_SINGLE_MODE, USM1_SELECT);

  USM_SensitivitySet(3,USM2_SELECT);
  USM_ModeSet(USM_SINGLE_MODE, USM2_SELECT);
}

///


/*=============================================
 * Ultrasonic Module 에서 현재 물체와의 거리를 
 *    read 한다.
 * 결과는 Cm 단위의 정수를 ARG에 넣는다.
 * return value : process OK : true.
 *                process Error = false.
 =============================================*/
bool USM1_EventFlag = off, USM2_EventFlag = off;
unsigned int USM_Distance = 0;

char USM_ReadDistance(unsigned int ret, char UMC_chanel_NO)
{
  unsigned char sum = 0;
  unsigned int retData;

  //DeviceSelect(1);
  DeviceSelect(UMC_chanel_NO);
  
  TxBuffer[0] = STX;
  TxBuffer[1] = 0x33;
  sum = 0x33;
  TxBuffer[2] = 0x49;
  sum += 0x49;
  TxBuffer[3] = ETX;
  sum += ETX;
  TxBuffer[4] = sum;
  Serial.write(TxBuffer, 5);
  Serial.flush(); // 전송 완료를 기다림.

  retData = DistanceData_Check();
  if (retData == 0) 
  {
    DeviceSelect(LCD_SELECT);
    return (false);
  }
  else
  {
    DeviceSelect(LCD_SELECT);
    return (true);
  }
}

/*=============================================
 * JT-LCD touch monitor 
 *      Active touch key set command.
 * 1 byte 8bit 가 각 키번호 (B0 ~ B7)에 해당하며,
 * 각 bit 는 
 *          1 = Active   (활성)
 *          0 = Inactive (비 활성)
 =============================================*/
 void TouchKey_ActiveControl(unsigned char KeyState)
{
  unsigned char sum = 0, ch;

  TxBuffer[0] = STX;      // Start of Text
  TxBuffer[1] = 0x35;     // Length
  sum = 0x35;
  TxBuffer[2] = 0x49;     // Command : Active Key set
  sum += 0x49;
  // Touch data set
  TxBuffer[3] = ((KeyState >> 4) & 0xf) | 0x30;
  sum += TxBuffer[3];
  TxBuffer[4] = (KeyState | 0x30) & 0xf;
  sum += TxBuffer[4];
  TxBuffer[5] = ETX;
  sum += ETX;
  TxBuffer[6] = sum;
  Serial.write(TxBuffer, 7);
  Serial.flush(); // 전송 완료를 기다림.

  if (AckNak_Check() == ACK) return (true);
  else return (false);
}


/*=============================================
 * Main loop...
 =============================================*/
const unsigned char MSG_Samp[10] = {0xC7, 0xD1, 0xB1, 0xDB, 0x20, 0x4B, 0x6F, 0x72,};  //"한글 Kor";
unsigned int DistReadIntervalCouinter = 0;
bool Double_Flag = off, USM_ToggleFlag = off;
char ch;

void loop()
{
  MainMenuDisplay();
  digitalWrite(13, LOW);  // LED off
  
  while(1)
  {
    wdt_reset();
    
    if (digitalRead(4) == LOW) // 터치 이벤트 발생 여부 확인.
    {
      if (TouchDataRead() == true) // 터치 데이터 읽기.
      {
        // Status LED  켜기.
        if (TouchState == 0) digitalWrite(13, LOW);
        else digitalWrite(13, HIGH);

        switch(TouchState)
        {
          case 0x80 : TouchTestProcess();   // Touch function test
                      MainMenuDisplay();
                      break;
          case 0x08 : if(BeepToggleFlag == on)      // Touch beep On/Off control.
                      {
                        TouchBeepFrequencySet(0); 
                        DrawString(8+64+(8*5),8,SINGLE,KeyMsg_Off,1);
                        BeepToggleFlag = off;
                      }
                      else
                      {
                        TouchBeepFrequencySet(14);
                        DrawString(8+64+(8*5),8,SINGLE,KeyMsg_On,1);
                        BeepToggleFlag = on;
                      }
                      break;
          case 0x40 : if(Double_Flag == off)          // sample message display.
                      {
                        DrawString(16,8+32,SINGLE,M_Menu_3,4);
                        DrawString(0,62,DOUBLE,"        ",8);//70
                        DrawString(0,70,SINGLE,MSG_Samp,8);//70
                        Double_Flag = on;
                      }
                      else
                      {
                        DrawString(16,8+32,SINGLE,M_Menu_2,4);
                        DrawString(0,62,DOUBLE,"        ",8);//70
                        DrawString(0,62,DOUBLE,MSG_Samp,8);//70
                        Double_Flag = off;
                      }
                      break;
          case 0x04 : 
//                      DrawString(16+64,8+32,SINGLE,"read",4);             // Distance read.
//                      ch = USM_ReadDistance(USM_Distance, USM1_SELECT);
//                      DrawString(16+64,8+32,SINGLE,M_Menu_5,4);
//                      if(ch == true)
//                      {
//                        DrawString(8 * 10,16 * 7,SINGLE,FirstDistStr,3);
//                      }
//                      else
//                      {
//                        DrawString(8 * 10,16 * 7,SINGLE," - ",3);
//                      }
                      break;
          default : break;
        }
      }
    }

    // 초음파 센서 1 이벤트 발생 여부 확인. (PD5)
    if (digitalRead(5) == LOW) 
    {
      if(USM1_EventFlag == off)
      {
        USM1_EventOnDisplay();
        USM1_EventFlag = on;
      }
    }
    else
    {
      if(USM1_EventFlag == on)
      {
        USM1_EventOffDisplay();
        USM1_EventFlag = off;
      }
    }

    // 초음파 센서 2 이벤트 발생 여부 확인. (PD6)
    if (digitalRead(6) == LOW) 
    {
      if(USM2_EventFlag == off)
      {
        USM2_EventOnDisplay();
        USM2_EventFlag = on;
      }
    }
    else
    {
      if(USM2_EventFlag == on)
      {
        USM2_EventOffDisplay();
        USM2_EventFlag = off;
      }
    }

    // 초음파 거리 측정값 resd & JT-LCD 에 표시.
    DistReadIntervalCouinter++;
    if(DistReadIntervalCouinter >= 10000)
    {
      DistReadIntervalCouinter = 0;

      if(USM_ToggleFlag == off)
      {
        // 초음파 모듈 1번 거리 
        if(USM_ReadDistance(USM_Distance, USM1_SELECT) == true)
        {
          DrawString(8 * 10,16 * 6,SINGLE,FirstDistStr,3);
        }
        else
        {
          DrawString(8 * 10,16 * 6,SINGLE," - ",3);
        }
        DrawString(8 * 14,16 * 6,SINGLE,"Cm",2);

        USM_ToggleFlag = on;
      }
      else
      {
        if(USM_ReadDistance(USM_Distance, USM2_SELECT) == true)
        {
          DrawString(8 * 10,16 * 7,SINGLE,FirstDistStr,3);
        }
        else
        {
          DrawString(8 * 10,16 * 7,SINGLE," - ",3);
        }
        DrawString(8 * 14,16 * 7,SINGLE,"Cm",2);

        USM_ToggleFlag = off;
      }
    }
  }
}

/*-------------------------------------------------
 * 기타 예제에 없는 command 는 유저 메뉴을 참고하여
 * 프로그램 바랍니다.
 ------------------------------------------------*/
